package com.qubi.exchange.entity;


import cn.hutool.json.JSONUtil;
import com.qubi.exchange.constant.OrderDirection;
import com.qubi.exchange.message.OrderMessage;
import com.qubi.exchange.websocket.DepthNotifyMessage;
import lombok.Data;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wx
 * @create 2019-02-11 14:42
 **/
@Data
public class OrderBook {

    public final ConcurrentSkipListMap<OrderMessage, OrderMessage> book;
    public final String direction;
    int priceScale;

    public final static int maxScaleCount = 4;

    public Map<BigDecimal, BigDecimal> depth;
    public Map<Integer, Map<BigDecimal, BigDecimal>> depthScale;


    public void initDepthMap() {
        depthScale = new HashMap<>(6);

        for (int i = 0; i < maxScaleCount; i++) {
            if (priceScale - i > 0) {

                if (i == 0) depthScale.put(priceScale, depth);
                else {
                    depthScale.put(priceScale - i, new ConcurrentHashMap<>());
                }
            }

        }


    }


    public static final Comparator<OrderMessage> SORT_BUY = (o1, o2) -> {
        int cmp = o2.price.compareTo(o1.price);
        cmp = cmp == 0 ? Long.compare(Long.valueOf(o1.id), Long.valueOf(o2.id)) : cmp;
        return cmp;
    };
    public static final Comparator<OrderMessage> SORT_SELL = (o1, o2) -> {
        int cmp = o1.price.compareTo(o2.price);
        cmp =cmp == 0 ? Long.compare(Long.valueOf(o1.id), Long.valueOf(o2.id)) : cmp;
        return cmp;
    };

    public OrderBook(boolean isBuy) {
        if (isBuy) {
            book = new ConcurrentSkipListMap<OrderMessage, OrderMessage>(SORT_BUY);
            direction = OrderDirection.BUY;
        } else {
            book = new ConcurrentSkipListMap<OrderMessage, OrderMessage>(SORT_SELL);
            direction = OrderDirection.SELL;
        }
        depth = new ConcurrentHashMap<>(400);


    }

    public OrderMessage getFirstKey() {
        return this.book.isEmpty() ? null : this.book.firstKey();
    }

    public OrderMessage getFirstItem() {
        OrderMessage key = getFirstKey();
        if (key == null) return null;
        return this.book.get(key);
    }

    public OrderMessage remove(OrderMessage key) {

        return book.remove(key);
    }

    public OrderMessage put(OrderMessage message) {
        this.book.put(message, message);
        return message;
    }

    public List<BigDecimal[]> getDepth(int size, int scale) {
        List<BigDecimal> result = new ArrayList<>(size);

        List<BigDecimal[]> depths = new ArrayList<>(size);
        BigDecimal[] lastDepth = null;
        int i = 1;
        for (Map.Entry<OrderMessage, OrderMessage> entry : book.entrySet()) {
            OrderMessage order = entry.getValue();
            if (lastDepth == null) {
                lastDepth = new BigDecimal[]{order.getPrice().setScale(scale, RoundingMode.DOWN), order.getRemain()};
                depths.add(lastDepth);
                i++;
            } else {
                if (order.getPrice().setScale(scale, RoundingMode.DOWN).compareTo(lastDepth[0]) == 0) {
                    lastDepth[1] = lastDepth[1].add(order.getRemain());
                } else {
                    if (i > size) {
                        break;
                    }
                    lastDepth = new BigDecimal[]{order.getPrice().setScale(scale, RoundingMode.DOWN), order.getRemain()};
                    depths.add(lastDepth);
                    i++;
                }
            }
        }
        // 填充不足的
        //for (; i <= size; i++) {
        //    lastDepth = new BigDecimal[]{BigDecimal.ZERO,BigDecimal.ZERO};
        //    depths.add(lastDepth);
        //}
        return depths;
    }

    public BigDecimal getSamePriceNumber(BigDecimal price){
        BigDecimal number = BigDecimal.ZERO;
        for (Map.Entry<OrderMessage, OrderMessage> entry : book.entrySet()) {
            OrderMessage order = entry.getValue();
            if (order.getPrice().compareTo(price)==0){
                number = number.add(order.getRemain());
            }
        }
        return number;

    }



}
